/*
 * report.c
 *
 *  Created on: 01/05/2013
 *      Author: jose
 */


#include <stdio.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <string.h>
#include <assert.h>
#include "error.h"
#include "algorithm.h"
#include "misc.h"

void
print_xml_tree(xmlNode * node, unsigned depth)
{
	xmlNode * ptr_node = NULL, * children = NULL;

    for (ptr_node = node; ptr_node; ptr_node = ptr_node->next)
    {
    	if (ptr_node->type == XML_ELEMENT_NODE)
    	{
    		printf("\n[%u] type: %u, name: %s content: %s", depth, ptr_node->type,
    					ptr_node->name, ptr_node->content);
    		printf("\n\tl");
    		for (children=ptr_node->children ; children ; children = children->next)
    		{
    			printf("\n\t--> type: %u, name: %s content: %s", children->type,
    						children->name, children->content);
    		}
    		printf("\n\n");
    	}
    	print_xml_tree(ptr_node->children, ++depth);
    }

}

/*
 * Input:
 * 	root: 		xmlNode que apunta al inicio del sub-árbol access
 * 	access:		Puntero a la estructura access, parte de session
 */
Access *
parse_access_tree(xmlNode * root, Access * access)
{
	assert(root);
	assert(access);

	xmlNode * ptr_node = NULL;

	for (ptr_node = root->children; ptr_node; ptr_node = ptr_node->next)
	{
		if(ptr_node->type == XML_ELEMENT_NODE)
		{
			/* Campo URL */
			if (!(xmlStrcmp(ptr_node->name, (const xmlChar *) "url")))
			{
				/* guardar URL */
				access->url = string_create_no_len(ptr_node->children->content);
				if (!(access->url))
				{
					error_message(__FILE__, __FUNCTION__, __LINE__, "Error cargar url a access");
					return NULL;
				}
			}
			/* Campo IP */
			else if (!(xmlStrcmp(ptr_node->name, (const xmlChar *) "timestamp")))
			{
				/* guardar timestamp */
				access->timestamp = string_create_no_len(ptr_node->children->content);
				if (!(access->timestamp))
				{
					error_message(__FILE__, __FUNCTION__, __LINE__, "Error cargar timestamp a access");
					return NULL;
				}
			}
			/* Campo port */
			else if (!(xmlStrcmp(ptr_node->name, (const xmlChar *) "port")))
			{
				/* TODO guardar port */
				access->port = atoi(ptr_node->children->content);
			}
		}
	}

	return access;
}


/*
 * Input:
 * 	root: 			xmlNode que apunta al inicio del sub-árbol session
 * 	session:		Puntero a la estructura session, parte de sessions
 */
Session *
parse_session_tree(xmlNode * root, Session * session)
{
	assert(root);
	assert(session);

	xmlNode * ptr_node = NULL;
	unsigned actual_access = 0;

	for (ptr_node = root->children; ptr_node; ptr_node = ptr_node->next)
	{
		if(ptr_node->type == XML_ELEMENT_NODE)
		{
			/* Campo IP */
			if (!(xmlStrcmp(ptr_node->name, (const xmlChar *) "ip")))
			{
				/* guardar ip */
				session->ip = string_create_no_len(ptr_node->children->content);
				if (!(session->ip))
				{
					error_message(__FILE__, __FUNCTION__, __LINE__, "Error cargar ip a session");
					return NULL;
				}
			}
			/* Campo len */
			else if (!(xmlStrcmp(ptr_node->name, (const xmlChar *) "len")))
			{
				/* guardar len */
				session->len = atoi(ptr_node->children->content);

				assert(session->len);

				/* Crear session */
				session->access = access_create(session->len);
				if (!(session->access))
				{
					error_message(__FILE__, __FUNCTION__, __LINE__, "Error crear access");
					return NULL;
				}
			}
			else if (!(xmlStrcmp(ptr_node->name, (const xmlChar *) "access")))
			{
				assert(actual_access < session->len);
				parse_access_tree(ptr_node, &(session->access[actual_access++]));
			}

		}

	}

	return session;
}



/*
 * Input:
 * 	root: 		xmlNode que apunta al inicio del sub-árbol sessions
 * 	sessions:	Puntero a la estructura sessions
 */
Sessions *
parse_sessions_tree(xmlNode * root, Sessions * sessions)
{
	assert(root);
	assert(sessions);

	xmlNode * ptr_node = NULL;
	unsigned actual_session = 0;

	for (ptr_node = root->children; ptr_node; ptr_node = ptr_node->next)
	{
		if(ptr_node->type == XML_ELEMENT_NODE)
		{
			/* Campo len */
			if (!(xmlStrcmp(ptr_node->name, (const xmlChar *) "len")))
			{
				sessions->len = atoi(ptr_node->children->content);

				assert(sessions->len > 0);

				/* Crear len-sesion */
				sessions->s = session_create(sessions->len);
				if (!(sessions->s))
				{
					error_message(__FILE__, __FUNCTION__, __LINE__, "Error crear sesión");
					return NULL;
				}
			}
			else if (!(xmlStrcmp(ptr_node->name, (const xmlChar *) "urls")))
			{
				sessions->total_urls = atoi(ptr_node->children->content);

				assert(sessions->total_urls > 0);
			}
			else if (!(xmlStrcmp(ptr_node->name, (const xmlChar *) "session")))
			{
				assert(actual_session < sessions->len);
				parse_session_tree(ptr_node, &(sessions->s[actual_session++]));
			}
		}

	}

	return sessions;
}




Sessions *
parse_dpireport_tree(xmlNode * root)
{
	assert(root);

	xmlNode * ptr_node = NULL;
	Sessions * s = NULL;

	for (ptr_node = root->children; ptr_node; ptr_node = ptr_node->next)
	{
		if(ptr_node->type == XML_ELEMENT_NODE)
		{
			/* Campo date */
			if (!(xmlStrcmp(ptr_node->name, (const xmlChar *) "date")))
			{
				/* TODO guardar fecha */
				;
			}
			else if (!(xmlStrcmp(ptr_node->name, (const xmlChar *) "sessions")))
			{
				s = sessions_create();
				/* Revisar si != NULL */
				if (!s)
				{
					error_message(__FILE__, __FUNCTION__, __LINE__, "Error asignacion de memoria a Sessions");
					return NULL;
				}

				s = parse_sessions_tree(ptr_node, s);
			}
		}

	}

	return s;
}

Sessions *
load_dpi_report(const char * filename)
{
	xmlDocPtr doc; /* Puntero a archivo XML */
	xmlNode * root = NULL ;	/* Puntero a nodo XML */
	Sessions * s = NULL;

	/* leer archivo xml */
    doc = xmlReadFile(filename, NULL, 0);
    if (!doc)
    {
        error_message(__FILE__, __FUNCTION__, __LINE__, "Error al abrir el reporte DPI");
        return NULL;
    }

    root = xmlDocGetRootElement(doc);

    if (xmlStrcmp(root->name, (const xmlChar *) "dpireport"))
    {
    	error_message(__FILE__, __FUNCTION__, __LINE__, "XML incorrecto (no es un reporte)");
    	xmlFreeDoc(doc);
    	return NULL;
    }

    print_xml_tree(root, 0);
    s = parse_dpireport_tree(root);

    /* Liberar memoria y otras variables utilizadas por el parser*/
    xmlFreeDoc(doc);
    xmlCleanupParser();

    return s;
}

